function equalsFn(a, b) {
	return a === b
}
class Node {
	constructor(element) {
		this.element = element
		this.next = undefined
	}
}
class DoublyNode extends Node {
	constructor(element, next, prev) {
		super(element, next)
		this.prev = prev
	}
}
export default class DoublyLinkedList {
	#count = 0
	#head = undefined
	#equalsFn = equalsFn
	#tail = undefined
	getElementAt(index) {
		if (index >= 0 && index <= this.#count) {
			let node = this.#head
			for (let i = 0; i < index && node !== null; i++) {
				node = node.next
			}
			return node
		}
		return undefined
	}
	insert(element, index) {
		if (index >= 0 && index <= this.#count) {
			const node = new DoublyNode(element)
			let current = this.#head
			if (index === 0) {
				if (this.#head == null) {
					this.#head = node
					this.#tail = node
				} else {
					node.next = this.#head
					current.prev = node
					this.#head = node
				}
			} else if (index === this.#count) {
				current = this.#tail
				current.next = node
				node.prev = current
				this.#tail = node
			} else {
				const previous = this.getElementAt(index - 1)
				current = previous.next
				node.next = current
				previous.next = node
				current.prev = node
				node.prev = previous
			}
			this.#count++
			return true
		}
		return false
	}
	removeAt(index) {
		if (index >= 0 && index <= this.#count) {
			let current = this.#head
			if (index === 0) {
				this.#head = current.next
				if (this.#count === 1) {
					this.#tail = undefined
				} else {
					this.#head.prev = undefined
				}
			} else if (index === this.#count - 1) {
				current = this.#tail
				this.#tail = current.prev
				this.#tail.next = undefined
			} else {
				current = this.getElementAt(index)
				const previous = current.prev
				previous.next = current.next
				current.next.prev = previous
			}
			this.#count--
			return true
		}
		return false
	}
	getHead() {
		return this.#head
	}
	getTail() {
		return this.#tail
	}
	isEmpty() {
		return this.size() === 0
	}
	size() {
		return this.#count
	}
	remove(element) {
		const index = this.indexOf(element)
		return this.removeAt(index)
	}
	indexOf(element) {
		let current = this.#head
		for (let i = 0; i < this.#count && current != null; i++) {
			if (this.#equalsFn(element, current.element)) {
				return i
			}
			current = current.next
		}
		return -1
	}
	toString() {
		if (this.#head == null) {
			return ''
		}
		let objString = `${this.#head.element}`
		let current = this.#head.next
		for (let i = 0; i < this.size() && current != null; i++) {
			objString = `${objString},${current.element}`
			current = current.next
		}
		return objString
	}
}
